import { isArray, isFunction, isObject, isString, wrapArray } from './uitils'
import { logError } from './uitils/log'
import Dep from './uitils/dep.js'
import {
  indexedDB,
  ACCESS_MODE,
  TRANSACTION_MODE,
  CURSOR_DIRECTION,
} from './uitils'

/**
 * 封装IndexDB底层API
 */
class IDB {
  constructor({ dbName, version }) {
    this.dbName = dbName
    this.version = version
    this.db = null
    this.idb = null
    this.table = []
    this._status = false // 是否先添加了表
    this._dep_ = new Dep()
  }

  /**
   * 打开数据库
   * */
  open() {
    // 打开前要先添加表
    if (this.table.length === 0 && !this._status) {
      logError('打开前要先用addTable添加表')
      return
    }

    if (typeof success !== 'function') {
      logError('open中success必须是一个function类型')
      return
    }

    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, this.version)

      request.onerror = (e) => {
        reject(e.target.error)
      }

      request.onsuccess = (e) => {
        this.db = e.target.result
        resolve(this.db)
      }

      request.onupgradeneeded = (e) => {
        this.idb = e.target.result

        this.table.forEach((tab) => {
          this.createTable(tab)
        })
      }
    })
  }

  //  关闭数据库
  async closeDB() {
    this.db.close()
  }

  // 删除数据库
  deleteDB() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.deleteDatabase(name)
      request.onsuccess = () => resolve()
      request.onerror = (e) => {
        reject(e.target.error)
      }
    })
  }

  /**
   * 清空某张表的数据
   */
  clearTable({ tableName }) {
    return new Promise((resolve, reject) => {
      const request = this.getDBStore(tableName, ACCESS_MODE.ReadWrite).clear()
      request.onsuccess = resolve
      request.onerror = reject
    })
  }

  /**
   * 添加一张表
   * @param tableOption<Object>
   * @tableName 表名
   * @option 表配置
   * @index 索引配置
   * */
  addTable(tableOption = {}) {
    this._status = false
    this.table.push(tableOption)
  }

  /**
   * @method 开启事务，获取数据表的Store对象
   * @param {String} 表名
   * @param {String} 事务权限
   * @return store
   * */
  getDBStore({
    tableName,
    mode = ACCESS_MODE.ReadWrite,
    option = TRANSACTION_MODE.Default,
  }) {
    if (!tableName) {
      throw new Error('in createTransaction,tableName is required')
    }
    const transaction = this.db.transaction(tableName, mode, option)
    return transaction.objectStore(tableName)
  }

  /**
   * 获取指定存储表的游标
   * @param {*} tableName 表名称
   * @param {*} range
   * @param {*} direction
   * @param {*} mode
   * @param {*} option
   */
  openDBStoreCursor({
    tableName,
    range,
    direction = CURSOR_DIRECTION.Next,
    mode = ACCESS_MODE.ReadWrite,
    option = TRANSACTION_MODE.Default,
  }) {
    return new Promise((resolve, reject) => {
      const store = this.getDBStore(tableName, mode, option)
      const req = store.openCursor(range, direction)
      req.onsuccess = (e) => {
        resolve(e.target.result)
      }
      req.onerror = (e) => {
        reject(e.target.error)
        console.error(e.target.error)
      }
    })
  }

  /**
   * 获取指定表的指定的索引
   * @param {*} param0
   */
  getDBIndex({
    tableName,
    indexName,
    mode = ACCESS_MODE.ReadWrite,
    option = TRANSACTION_MODE.Default,
  }) {
    return this.getDBStore(tableName, mode, option).index(indexName)
  }

  /**
   * 打开指定表的指定索引的游标
   * @param {*} param0
   */
  openDBIndexCursor({
    tableName,
    indexName,
    range,
    handler,
    direction = CURSOR_DIRECTION.Next,
    mode = ACCESS_MODE.ReadWrite,
    option = TRANSACTION_MODE.Default,
  }) {
    if (!handler && !isFunction(handler)) {
      throw new Error('handler为必要的Function类型的参数！')
    }
    const index = this.getDBIndex({ tableName, indexName, mode, option })
    const req = index.openCursor(range, direction)
    req.onsuccess = (e) => {
      handler(e.target.result)
    }

    req.onerror = (e) => {
      console.error(e.target.error)
    }
  }

  /**
   * 创建table
   * @option<Object>  keyPath指定主键 autoIncrement是否自增
   * @index 索引配置
   * */
  createTable({ tableName, option, indexs = [] }) {
    if (!this.idb.objectStoreNames.contains(tableName)) {
      const store = this.idb.createObjectStore(tableName, option)
      for (const indexItem of indexs) {
        this.createIndex(store, indexItem)
      }
    }
  }

  /**
   * 创建索引
   * @option<Object> unique是否是唯一值
   * */
  createIndex(store, { key, option }) {
    if (isString(store)) {
      store = this.getDBStore({ store })
    }
    return store.createIndex(key, key, option)
  }

  /**
   * 删除一个表
   * @param {*} tableName
   */
  dropTable(tableName) {
    return this.idb.deleteObjectStore(tableName)
  }
}

export default IDB
